/*
 * =====================================================================================
 *
 *       Filename:  Builder.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2015年01月31日 10时08分19秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  LiuYi (), swliuyi@gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <limits.h>
#include <iostream>
#include  <vector>
#include  <memory>

using namespace std;
class Product
{
    private:
        vector<string> parts;
    public:
        void Add(string part)
        {
            parts.push_back(part);
        }
        void show()
        {
            cout<<"Build Product"<<endl;
            for( size_t i = 0 ; i < parts.size() ; i++ )
            {
                cout<<parts[i]<<endl;
            }
        }
};

class Builder
{
    public:
        virtual void BuildPartA() = 0;
        virtual void BuildPartB() = 0;
        virtual Product * GetResult() = 0;
};

class ConcreteBuilder1 : public Builder//工厂类不应该使用智能指针，其返回的产品对象，应该由产品本身析构
{
    private:
        Product * p;        
    public:
        ConcreteBuilder1():p(new Product()){}
        ~ConcreteBuilder1(){}
        void BuildPartA()
        {
            p->Add("A");
        }
        void BuildPartB()
        {
            p->Add("B");
        }
        Product* GetResult()
        {
            return p;
        }
};

class ConcreteBuilder2 : public Builder
{
    private:
        Product *p;        
    public:
        ConcreteBuilder2():p(new Product()){}
        ~ConcreteBuilder2(){}
        void BuildPartA()
        {
            p->Add("X");
        }
        void BuildPartB()
        {
            p->Add("Y");
        }
        Product* GetResult()
        {
            return p;
        }
};

class Director
{
    public:
        static void Construct(Builder * build)
        {
            build->BuildPartA();
            build->BuildPartB();
        }
};

int main(int argc, char *argv[])
{
    shared_ptr<ConcreteBuilder1> b1(new ConcreteBuilder1());
    Director::Construct(b1.get());
    shared_ptr<Product> p1(b1->GetResult());
    p1->show();

    shared_ptr<ConcreteBuilder2> b2(new ConcreteBuilder2());
    Director::Construct(b2.get());
    shared_ptr<Product> p2(b2->GetResult());
    p2->show();
}
